#ifndef _VISITER_IMP_
#define _VISITER_IMP_

#include "ParseTree.h"
#include "Value.h"
#include <SymtableInterface.h>
#include <iostream>

using namespace std;

class InterpreterException {
	char* msg;

public:
	InterpreterException(char* msg);
	void setMsg(char* msg);
	virtual char* getMessage();
};

class InterpreterUndefinedVariableException : public InterpreterException {
public:
	InterpreterUndefinedVariableException(Token* token);
	virtual char* getMessage();
};

/**
* Evaluator. Besitzt die einzelnen Regeln, wie der ParseTree evalutiert werden muss. Führt Rechenoperationen bzw.
* die einzelnen Funktionen aus. Als argument benötigen die Methoden jeweils den (Teil-)Baum.
*/
class EvaluatorImp : public Evaluator {
	/// Pointer of symtable. Needed to store values into it
	SymtableInterface* symtable;
	int explistOpType;

	/**
	* Stores a value into the symtable
	*
	* @param lexem		Pointer of lexem which points to the lexem in the symtable
	* @param length		Length of lexem
	* @param value		Pointer of value
	*
	* @return			void
	*/
	void store(char* lexem, int length, Value* value);

public:
	EvaluatorImp(SymtableInterface* symtable);

	/**
	* Evaluates Node StatementList.
	*
	* @param tree	Parse tree which will be evaluated
	*
	* @return		void
	*/
	virtual void eval_StatementList(Tree* tree);

	/**
	* Evaluates Node StatementList2. Accepts left node and if exists, right node
	*
	* @param tree	Parse tree which will be evaluated
	*
	* @return		void
	*/
	virtual void eval_StatementList2(Tree* tree);

	/**
	* Evaluates Node Statement1. Gets lexem by left leaf and value by right node.
	* Afterwards, the value will be stored with lexem into the symtable
	*
	* @param tree	Parse tree which will be evaluated
	*
	* @return		void
	*/
	virtual void eval_Statement_1(Tree* tree);

	/**
	* Evaluates Node Statement2. Gets value by left node and displays it on the console
	*
	* @param tree	Parse tree which will be evaluated
	*
	* @return		void
	*/
	virtual void eval_Statement_2(Tree* tree);

	/**
	* Evaluates Node EXP. Accepts left and if exists right node.
	*
	* @param tree	Parse tree which will be evaluated
	*
	* @return		value as result of the operation or value from EXP
	*/
	virtual Value* eval_Exp(Tree* tree);

	/**
	* Evaluates Node EXP2/EXP3. Accepts left node
	*
	* @param tree	Parse tree which will be evaluated
	*
	* @return		value as result of the accept method
	*/
	virtual Value* eval_Exp2_Exp3(Tree* tree);

	/**
	* Evaluates Node EXP2/Int. Gets integer by left leaf and creates a new integer object
	* without an operator
	*
	* @param tree	Parse tree which will be evaluated
	*
	* @return		integer object
	*/	
	virtual Value* eval_Exp2_Int(Tree* tree);

	/**
	* Evaluates Node EXP2/Real. Gets real by left leaf and creates a new real object
	* without an operator
	*
	* @param tree	Parse tree which will be evaluated
	*
	* @return		real object
	*/
	virtual Value* eval_Exp2_Real(Tree* tree);

	/**
	* Evaluates Node EXP2/Negation. Gets value by left node and negates it
	*
	* @param tree	Parse tree which will be evaluated
	*
	* @return		value as negated result of EXP2
	*/
	virtual Value* eval_Exp2_MinusExp2(Tree* tree);

	virtual Value* eval_Exp2_Sum(Tree* tree);

	virtual Value* eval_Exp2_Prod(Tree* tree);

	virtual Value* eval_Exp3_1(Tree* tree);

	/**
	* Evaluates Node EXP3/identifier. Gets identifier by left node.
	* Afterwards the value of the identifier will be looked up from symtable
	*
	* @param tree	Parse tree which will be evaluated
	*
	* @return		value from identifier
	*/
	virtual Value* eval_Exp3_2(Tree* tree);

	virtual Value* eval_ExpList(Tree* tree);

	virtual Value* eval_ExpList2(Tree* tree);

	virtual Value* eval_OP_Exp_1(Tree* tree);

	virtual Value* eval_OP_Exp_2(Tree* tree);

	virtual Value* eval_OP_Plus(Tree* tree);

	virtual Value* eval_OP_Minus(Tree* tree);

	virtual Value* eval_OP_Mult(Tree* tree);

	virtual Value* eval_OP_Div(Tree* tree);

	virtual Value* eval_OP_Durch(Tree* tree);

	virtual Value* eval_OP_Mod(Tree* tree);
};

#endif //_VISITER_IMP_